﻿#include "pch.h"
#include "WindowsWindow.h"

#include "core/log/LogSystem.h"
#include "function/EventSystem/ApplicationEvent.h"
#include "function/EventSystem/KeyEvent.h"
#include "function/EventSystem/MouseEvent.h"
#include "function/RenderSystem/OpenGL/OpenGLContext.h"

namespace Engine
{
	static bool glfwInitialized = false;

	WindowsWindow::WindowsWindow(const WindowProps& props)
	{
		data.Title = props.Title;
		data.Width = props.Width;
		data.Height = props.Height;

		if (!glfwInitialized)
		{
			const int success = glfwInit();
			ENGINE_ASSERT(success, "初始化GLFW失败!")

			glfwSetErrorCallback([](const int error, const char* description)
			{
				ENGINE_ERROR("GLFW 错误 ({0}):{1}", error, description)
			});

			glfwInitialized = true;
		}

		window = glfwCreateWindow(props.Width, props.Height, props.Title.c_str(), nullptr, nullptr);
		if (window == nullptr)
		{
			glfwTerminate();
			ENGINE_ERROR("创建窗口失败！")
		}
		else
		{
			ENGINE_TRACE("创建窗口 {0}（宽：{1}，高：{2}）", props.Title, props.Width, props.Height)

			renderContext = new OpenGLContext(window);
			renderContext->Init();
		}

		glfwSetWindowUserPointer(window, &data);

		glfwSetWindowSizeCallback(window, [](GLFWwindow* window, const int width, const int height)
		{
			WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));
			data.Width = width;
			data.Height = height;

			WindowResizeEvent event(width, height);
			data.Callback(event);
		});

		glfwSetWindowCloseCallback(window, [](GLFWwindow* window)
		{
			const WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));

			WindowCloseEvent event;
			data.Callback(event);
		});

		glfwSetKeyCallback(window, [](GLFWwindow* window, const int key, int scancode, const int action, int mods)
		{
			const WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));

			switch (action)
			{
				case GLFW_PRESS:
					{
						KeyPressedEvent event(key, false);
						data.Callback(event);
						break;
					}
				case GLFW_RELEASE:
					{
						KeyReleasedEvent event(key);
						data.Callback(event);
						break;
					}
				case GLFW_REPEAT:
					{
						KeyPressedEvent event(key, true);
						data.Callback(event);
						break;
					}
				default:
					break;
			}
		});

		glfwSetMouseButtonCallback(window, [](GLFWwindow* window, const int button, const int action, int mods)
		{
			const WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));

			switch (action)
			{
				case GLFW_PRESS:
					{
						MouseButtonPressedEvent event(button);
						data.Callback(event);
						break;
					}
				case GLFW_RELEASE:
					{
						MouseButtonReleasedEvent event(button);
						data.Callback(event);
						break;
					}
				default: 
					break;
			}
		});

		glfwSetScrollCallback(window, [](GLFWwindow* window, const double xOffset, const double yOffset)
		{
			const WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));

			MouseScrolledEvent event(xOffset, yOffset);
			data.Callback(event);
		});

		glfwSetCursorPosCallback(window, [](GLFWwindow* window, const double xPos, const double yPos)
		{
			const WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));

			MouseMovedEvent event(xPos, yPos);
			data.Callback(event);
		});

		glfwSetCharCallback(window, [](GLFWwindow* window, const unsigned int keyCode)
		{
			const WindowData& data = *static_cast<WindowData*>(glfwGetWindowUserPointer(window));

			KeyTypedEvent event(keyCode);
			data.Callback(event);
		});
	}

	WindowsWindow::~WindowsWindow()
	{
		glfwDestroyWindow(window);
	}

	AbstractWindow* AbstractWindow::Create(const WindowProps& props)
	{
		return new WindowsWindow(props);
	}

	void WindowsWindow::OnUpdate()
	{
		glfwPollEvents();
		renderContext->SwapBuffers();
	}

	void WindowsWindow::SetVSync(const bool enable)
	{
		if (enable)
		{
			glfwSwapInterval(1);
		}
		else
		{
			glfwSwapInterval(0);
		}

		data.VSync = enable;
	}
}
